﻿using System.IO;
using System.Collections.Generic;
using UnityEngine;
using VoxelBlock.VoxelInput;

namespace VoxelBlock.PackMod
{
    public class VoxelPackToMesh : MonoBehaviour
    {
        void Start()
        {
            //RioVoxelData riovox = RioVoxelDataIO.Open(@"F:\Voxel测试程序研究室\新Voxel文件读取器\test.riovox");
            //CreateModel(riovox);
            //return;


            List<int> boneIndexs = new List<int>();
            List<byte[]> allByteData = new List<byte[]>();
            List<Vector3> allPosition = new List<Vector3>();


            List<Transform> fmAllTransform;
            Transform skeletonPoint = GameObject.FindObjectOfType<MainSkeletonComponent>().transform;
            Dictionary<int, int> dicInstanceToIndex ;
            fmAllTransform = GetAllTransform(skeletonPoint, out dicInstanceToIndex);


            UnitMeshPointComponent[] allUnitMeshPointComponent = GameObject.FindObjectsOfType<UnitMeshPointComponent>();
            foreach (var item in allUnitMeshPointComponent)
            {
                if (item.m_boneTarget)
                {
                    DrawVoxel3DCoreComponent drawComponent = item.GetComponent<DrawVoxel3DCoreComponent>();

                    VoxelInput.VoxelInputInfo itemVoxelInputInfo = VoxelBlock.VoxelBlock3D.OperateCreate3D.GetFileVoxelData(drawComponent.mainDrawVoxel3DCore);

                    //Vector3 position = new Vector3(itemVoxelInputInfo.SizeX / 2f, itemVoxelInputInfo.SizeY / 2f, itemVoxelInputInfo.SizeZ / 2f);
                    Vector3 position2 = new Vector3(itemVoxelInputInfo.minX , itemVoxelInputInfo.minY, itemVoxelInputInfo.minZ);
                    allPosition.Add(-( position2 + item.transform.position - item.GetComponent<TransformUnitComponent>().zeroPosition));
                    
                    //item.transform.position

                    allByteData.Add(VoxelInput.VoxelInput.SetVoxelData(itemVoxelInputInfo));
                    boneIndexs.Add(dicInstanceToIndex[item.m_boneTarget.GetInstanceID()]);



                    /*drawComponent.mainDrawVoxel3DCore.RootTransform*//*item.transform.position*/
                    /*- item.GetComponent<TransformUnitComponent>().minPosition*/
                }
            }
            Show(boneIndexs, allByteData, allPosition, fmAllTransform);
        }

        public static void CreateModel(RioVoxelData riovoxData)
        {
            VoxelBoneTransform[] boneTransforms = riovoxData.transforms;

            Transform[] transforms = new Transform[boneTransforms.Length];
            Vector3[] pivots = new Vector3[boneTransforms.Length];
            Vector3Int[] allVoxelSize = new Vector3Int[boneTransforms.Length];
            for (int i = 0; i < boneTransforms.Length; i++)
            {
                allVoxelSize[i] = riovoxData.allVoxel[i].size;
            }
            Color32[] colors = riovoxData.colors;
            byte[][] allVoxelByteData = new byte[boneTransforms.Length][];
            for (int i = 0; i < boneTransforms.Length; i++)
            {
                allVoxelByteData[i] = riovoxData.allVoxel[i].voxelData;
            }
            int[] boneIndexs = new int[boneTransforms.Length];



            GameObject fmGameObject = new GameObject("Bruce");
            fmGameObject.transform.position = new Vector3(0, 0, 0);
            fmGameObject.transform.localScale = new Vector3(1, 1, 1);
            fmGameObject.transform.rotation = Quaternion.identity;
            for (int i = 0; i < transforms.Length; i++)
            {
                VoxelBoneTransform boneTransform = boneTransforms[i];
                GameObject gameobj = new GameObject(boneTransform.name);
                Transform transform = gameobj.transform;
                if (boneTransform.parent == null)
                {
                    transform.parent = fmGameObject.transform;
                }
                else
                {
                    transform.parent = transforms[boneTransform.parentIndex];
                }
                transform.localPosition = boneTransform.localPosition;
                transform.localEulerAngles = boneTransform.localEulerAngles;
                transform.localScale = boneTransform.localScale;
                pivots[i] = boneTransform.pivot;

                transforms[i] = transform;
                boneIndexs[i] = i;
            }

            ShowRiovox(fmGameObject, boneIndexs, allVoxelByteData, allVoxelSize, pivots, transforms, colors);
        }
        //struct Bone

        public static void ShowRiovox(GameObject fmGameObject, int[] boneIndexs, byte[][] allVoxelByteData, Vector3Int[] allVoxelSize, Vector3[] pivots, Transform[] allTransform, Color32[] colors)
        {
            //byte[] aByteData = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\niuniu.vox");
            //byte[] aByteData2 = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\chr_rain.slab.vox");

            List<VoxelSurfaceData> voxelSurfaceDatasbool1;
            //List<VoxelSurfaceData> voxelSurfaceDatasbool2;


            GameObject fmGameObjectSkinnedMeshRenderer = new GameObject("SkinnedMeshRenderer");
            fmGameObjectSkinnedMeshRenderer.transform.parent = fmGameObject.transform;
            fmGameObjectSkinnedMeshRenderer.transform.localPosition = new Vector3(0, 0, 0);
            fmGameObjectSkinnedMeshRenderer.transform.localScale = new Vector3(1, 1, 1);
            fmGameObjectSkinnedMeshRenderer.transform.localRotation = Quaternion.identity;


            VoxelBlock.PackMod.ReduceMemorySubsectionRioVoxelToMesh fmVoxelToMesh = new ReduceMemorySubsectionRioVoxelToMesh(colors);
            SkinnedMeshRenderer fmSkinnedMeshRenderer = fmGameObjectSkinnedMeshRenderer.AddComponent<SkinnedMeshRenderer>();
            Mesh fmMesh = new Mesh();
            Material fmMaterial = new Material(Shader.Find("Mobile/Diffuse"));
            MyTexture2D fmTexture;


            List<Vector3> vertices = new List<Vector3>();
            List<int> verticeLengths = new List<int>();

            int[] triangles;
            Vector2[] uv;

            Transform skeletonPoint = allTransform[0];
            fmSkinnedMeshRenderer.bones = allTransform;

            //for (int i = 0; i < allByteData.Count; i++)
            //{
            //    File.WriteAllBytes(@"C:\Users\Administrator\Desktop\OK" + i + ".vox", allByteData[i]);
            //}

            //byte[] aByteData = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\niuniu.vox");
            //byte[] aByteData2 = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\chr_rain.slab.vox");
            //allByteData[0] = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\niuniu.vox");
            //allByteData[1] = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\chr_rain.slab.vox");
            for (int i = 0; i < allVoxelSize.Length; i++)
            {
                var myVertices = fmVoxelToMesh.GetVertices(allVoxelByteData[i], allVoxelSize[i], pivots[i], true);//
                vertices.AddRange(myVertices);
                verticeLengths.Add(myVertices.Length);
            }

            fmTexture = fmVoxelToMesh.Over(out triangles, out uv, out voxelSurfaceDatasbool1);

            BoneWeight[] boneWeights = new BoneWeight[vertices.Count];//最终的骨骼量。
            int weightsIndex = 0;//开始索引
            //设置Vox的骨骼量。
            for (int i = 0; i < verticeLengths.Count; i++)
            {
                for (int max = weightsIndex + verticeLengths[i]; weightsIndex < max; weightsIndex++)
                {
                    boneWeights[weightsIndex] = new BoneWeight();
                    boneWeights[weightsIndex].boneIndex0 = boneIndexs[i];
                    boneWeights[weightsIndex].weight0 = 1f;
                }
            }

            int bonesLength = fmSkinnedMeshRenderer.bones.Length;
            //计算矩阵
            Matrix4x4[] bindposes = new Matrix4x4[bonesLength];
            for (int i = 0; i < bonesLength; i++)
            {
                bindposes[i] = fmSkinnedMeshRenderer.bones[i].worldToLocalMatrix;
            }


            //ReduceMemoryVoxelToMesh fmReduceMemoryVoxelToMesh2 = new ReduceMemoryVoxelToMesh();
            //MyTexture2D newTexture;
            //MyMesh mesh2 = fmReduceMemoryVoxelToMesh2.GetMeshOrTexture(allByteData[0], out newTexture, allPosition[0], out voxelSurfaceDatasbool2, true);


            //Debug.Log(vertices.Count);
            //Debug.Log(mesh2.vertices.Length);
            //bool isok = true;
            //for (int i = 0; i < vertices.Count; i++)
            //{
            //    if (vertices[i] == mesh2.vertices[i])
            //    {

            //    }
            //    else
            //    {
            //        Debug.LogError(i); isok = false;
            //        break;
            //    }
            //}
            //Debug.Log(isok);

            //Debug.Log(voxelSurfaceDatasbool1.Count);
            //Debug.Log(voxelSurfaceDatasbool2.Count);
            //isok = true;
            //for (int i = 0; i < voxelSurfaceDatasbool2.Count; i++)
            //{
            //    if (voxelSurfaceDatasbool1[i] .Equals( voxelSurfaceDatasbool2[i]) )
            //    {

            //    }
            //    else
            //    {
            //        Debug.LogError(i); isok = false;
            //        break;
            //    }
            //}
            //Debug.Log(isok);

            //     /*
            fmMesh.vertices = vertices.ToArray();
            fmMesh.triangles = triangles;
            fmMesh.uv = uv;
            fmMesh.boneWeights = boneWeights;
            fmMesh.bindposes = bindposes;
            fmMesh.RecalculateNormals();
            fmSkinnedMeshRenderer.sharedMesh = fmMesh;

            fmMaterial.mainTexture = fmTexture.ToTexture2D();
            fmSkinnedMeshRenderer.material = fmMaterial;
            /* */

            /*
        fmMesh.vertices = mesh2.vertices;
        fmMesh.triangles = mesh2.triangles;
        fmMesh.uv = mesh2.uv;
        fmMesh.RecalculateNormals();
        fmSkinnedMeshRenderer.sharedMesh = fmMesh;
        fmMaterial.mainTexture = newTexture.ToTexture2D();
        fmSkinnedMeshRenderer.material = fmMaterial;
        /* */
            //File.WriteAllBytes(@"C:\Users\Administrator\Desktop\A.png", newTexture.ToTexture2D().EncodeToPNG());
            //File.WriteAllBytes(@"C:\Users\Administrator\Desktop\B.png", fmTexture.ToTexture2D().EncodeToPNG());



            AssetData ass = GameObject.FindObjectOfType<AssetData>();
            ass.asset.Add(fmMesh);
            ass.path.Add("Mesh");
            ass.asset.Add(fmMaterial.mainTexture);
            ass.path.Add("mainTexture");
        }

        public void Show(List<int> boneIndexs, List<byte[]> allByteData, List<Vector3> allPosition, List<Transform> aAllTransform)
        {
            //byte[] aByteData = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\niuniu.vox");
            //byte[] aByteData2 = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\chr_rain.slab.vox");

            List<VoxelSurfaceData> voxelSurfaceDatasbool1;
            //List<VoxelSurfaceData> voxelSurfaceDatasbool2;


            GameObject fmGameObject = new GameObject("Pack");
            GameObject fmGameObjectSkinnedMeshRenderer = new GameObject("SkinnedMeshRenderer");
            fmGameObjectSkinnedMeshRenderer.transform.parent = fmGameObject.transform;
            fmGameObjectSkinnedMeshRenderer.transform.localPosition = new Vector3(0, 0, 0);
            fmGameObjectSkinnedMeshRenderer.transform.localScale = new Vector3(1, 1, 1);
            fmGameObjectSkinnedMeshRenderer.transform.localRotation = Quaternion.identity;
            fmGameObject.transform.position = new Vector3(0, 0, 0);
            fmGameObject.transform.localScale = new Vector3(1, 1, 1);
            fmGameObject.transform.rotation = Quaternion.identity;
            VoxelBlock.PackMod.ReduceMemoryVoxelToMesh fmVoxelToMesh = new ReduceMemoryVoxelToMesh();
            SkinnedMeshRenderer fmSkinnedMeshRenderer = fmGameObjectSkinnedMeshRenderer.AddComponent<SkinnedMeshRenderer>();
            Mesh fmMesh = new Mesh();
            Material fmMaterial = new Material(Shader.Find("Mobile/Diffuse"));
            MyTexture2D fmTexture;


            List<Vector3> vertices = new List<Vector3>();
            List<int> verticeLengths = new List<int>();

            int[] triangles;
            Vector2[] uv;

            Transform skeletonPoint = aAllTransform[0];
            skeletonPoint.parent = fmGameObject.transform;
            skeletonPoint.localPosition = new Vector3(0, 0, 0);
            skeletonPoint.localScale = new Vector3(1, 1, 1);
            skeletonPoint.localRotation = Quaternion.identity;
            fmSkinnedMeshRenderer.bones = aAllTransform.ToArray();

            //for (int i = 0; i < allByteData.Count; i++)
            //{
            //    File.WriteAllBytes(@"C:\Users\Administrator\Desktop\OK" + i + ".vox", allByteData[i]);
            //}

            //byte[] aByteData = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\niuniu.vox");
            //byte[] aByteData2 = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\chr_rain.slab.vox");
            //allByteData[0] = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\niuniu.vox");
            //allByteData[1] = File.ReadAllBytes(@"C:\Users\Administrator\Desktop\chr_rain.slab.vox");
            for (int i = 0; i < allByteData.Count; i++)
            {
                var myVertices = fmVoxelToMesh.GetVertices(allByteData[i], allPosition[i], true);//
                vertices.AddRange(myVertices);
                verticeLengths.Add(myVertices.Length);
            }

            fmTexture = fmVoxelToMesh.Over(out triangles, out uv, out voxelSurfaceDatasbool1);

            BoneWeight[] boneWeights = new BoneWeight[vertices.Count];//最终的骨骼量。
            int weightsIndex = 0;//开始索引
            //设置Vox的骨骼量。
            for (int i = 0; i < verticeLengths.Count; i++)
            {
                for (int max = weightsIndex + verticeLengths[i]; weightsIndex < max; weightsIndex++)
                {
                    boneWeights[weightsIndex] = new BoneWeight();
                    boneWeights[weightsIndex].boneIndex0 = boneIndexs[i];
                    boneWeights[weightsIndex].weight0 = 1f;
                }
            }

            int bonesLength = fmSkinnedMeshRenderer.bones.Length;
            //计算矩阵
            Matrix4x4[] bindposes = new Matrix4x4[bonesLength];
            for (int i = 0; i < bonesLength; i++)
            {
                bindposes[i] = fmSkinnedMeshRenderer.bones[i].worldToLocalMatrix;
            }


            //ReduceMemoryVoxelToMesh fmReduceMemoryVoxelToMesh2 = new ReduceMemoryVoxelToMesh();
            //MyTexture2D newTexture;
            //MyMesh mesh2 = fmReduceMemoryVoxelToMesh2.GetMeshOrTexture(allByteData[0], out newTexture, allPosition[0], out voxelSurfaceDatasbool2, true);
                 

            //Debug.Log(vertices.Count);
            //Debug.Log(mesh2.vertices.Length);
            //bool isok = true;
            //for (int i = 0; i < vertices.Count; i++)
            //{
            //    if (vertices[i] == mesh2.vertices[i])
            //    {

            //    }
            //    else
            //    {
            //        Debug.LogError(i); isok = false;
            //        break;
            //    }
            //}
            //Debug.Log(isok);

            //Debug.Log(voxelSurfaceDatasbool1.Count);
            //Debug.Log(voxelSurfaceDatasbool2.Count);
            //isok = true;
            //for (int i = 0; i < voxelSurfaceDatasbool2.Count; i++)
            //{
            //    if (voxelSurfaceDatasbool1[i] .Equals( voxelSurfaceDatasbool2[i]) )
            //    {

            //    }
            //    else
            //    {
            //        Debug.LogError(i); isok = false;
            //        break;
            //    }
            //}
            //Debug.Log(isok);

            //     /*
             fmMesh.vertices = vertices.ToArray();
             fmMesh.triangles = triangles;
             fmMesh.uv = uv;
             fmMesh.boneWeights = boneWeights;
             fmMesh.bindposes = bindposes;
             fmMesh.RecalculateNormals();
             fmSkinnedMeshRenderer.sharedMesh = fmMesh;

             fmMaterial.mainTexture = fmTexture.ToTexture2D();
             fmSkinnedMeshRenderer.material = fmMaterial;
             /* */

                /*
            fmMesh.vertices = mesh2.vertices;
            fmMesh.triangles = mesh2.triangles;
            fmMesh.uv = mesh2.uv;
            fmMesh.RecalculateNormals();
            fmSkinnedMeshRenderer.sharedMesh = fmMesh;
            fmMaterial.mainTexture = newTexture.ToTexture2D();
            fmSkinnedMeshRenderer.material = fmMaterial;
            /* */
            //File.WriteAllBytes(@"C:\Users\Administrator\Desktop\A.png", newTexture.ToTexture2D().EncodeToPNG());
            //File.WriteAllBytes(@"C:\Users\Administrator\Desktop\B.png", fmTexture.ToTexture2D().EncodeToPNG());



            AssetData ass = GameObject.FindObjectOfType<AssetData>();
            ass.asset.Add(fmMesh);
            ass.path.Add("Mesh");
            ass.asset.Add(fmMaterial.mainTexture);
            ass.path.Add("mainTexture");
        }

        public static List<Transform> GetAllTransform(Transform mainTransform,out Dictionary<int, int> dicInstanceToIndex)
        {
            dicInstanceToIndex = new Dictionary<int, int>();
            List<Transform> allTransform = new List<Transform>();
            var newMainTransform = Copy(mainTransform, null);
            allTransform.Add(newMainTransform);
            foreach (Transform item in mainTransform)
            {
                var newItem = Copy(item, newMainTransform);
                dicInstanceToIndex[item.GetInstanceID()] = allTransform.Count;
                allTransform.Add(newItem);
                GetAllTransform(allTransform, dicInstanceToIndex, item, newItem);
            }
            return allTransform;
        }

        public static void GetAllTransform(List<Transform> allTransform, Dictionary<int, int> dicInstanceToIndex, Transform mainTransform, Transform aNewMainTransform)
        {
            foreach (Transform item in mainTransform)
            {
                var newItem = Copy(item, aNewMainTransform);
                dicInstanceToIndex[item.GetInstanceID()] = allTransform.Count;
                allTransform.Add(newItem);
                if (item.childCount > 0)
                {
                    GetAllTransform(allTransform, dicInstanceToIndex, item, newItem);
                }
            }
        }

        //public static List<string> GetAllTransform(Transform mainTransform, out List<Transform> allTransform)
        //{
        //    List<string> allTransformName = new List<string>();
        //    allTransform = new List<Transform>();

        //    allTransformName.Add(mainTransform.name);
        //    //allTransform.Add(mainTransform);
        //    var newMainTransform = Copy(mainTransform, null);
        //    allTransform.Add(newMainTransform);

        //    foreach (Transform item in mainTransform)
        //    {
        //        allTransformName.Add(mainTransform.name + "/" + item.name);
        //        //allTransform.Add(item);
        //        allTransform.Add(Copy(item, newMainTransform));
        //    }

        //    GetAllTransform(mainTransform, null, mainTransform.name, allTransform, allTransformName);
        //    return allTransformName;
        //}

        //private static void GetAllTransform(Transform mainTransform, Transform newMainTransform, string transformName, List<Transform> allTransform, List<string> allTransformName)
        //{
        //    allTransformName.Add(transformName);
        //    //allTransform.Add(mainTransform);
        //    var newmainTransform = Copy(mainTransform, newMainTransform);
        //    allTransform.Add(newmainTransform);
        //    if (mainTransform.childCount > 0)
        //    {
        //        foreach (Transform item in mainTransform)
        //        {
        //            GetAllTransform(item, newmainTransform, transformName + "/" + item.name, allTransform, allTransformName);
        //        }
        //    }
        //}

        private static Transform Copy (Transform aTransform, Transform parent)
        {
            Transform goitem = new GameObject(aTransform.name).transform;
            goitem.parent = parent;
            goitem.localPosition = aTransform.localPosition;
            goitem.localScale = aTransform.localScale;
            goitem.localRotation = aTransform.localRotation;
            return goitem;
        }

    }
}
